/**
 * SK Communications' Javascript Framework FSZ
 * @version 0.3.9
 * @author SK Communications UI Development Team.
 */

if (!window.Fsz) {
  Fsz = {};
  Fsz.version = '0.3.9.0.1';
  Fsz.extend = function() {
    if (arguments.length > 1) {
      var obj = arguments[1];
      var target = arguments[0];
      for (var key in obj) {
        target[key] = obj[key];
      }
    } else {
      var obj = arguments[0];
      for (var key in obj) {
        Fsz[key] = obj[key];
      }
    }
  }
  Fsz.d = document;
}
/**
 * Fsz base method.
 */
Fsz.extend({
  emptyFunction: function() {}
});

/**
 * @TODO 프로토타입 확장 메쏘드.
 */
Fsz.extendPrototype = function(appendTarget, object, overwrite) {
  var addedMethods = 0;
  for (var method in object) {
    if (overwrite == true || appendTarget.hasOwnProperty(method) == false) {
      appendTarget.prototype[method] = object[method];
      addedMethods++;
    }
  }
  return addedMethods;
};

Fsz.$Array = function(arr) {
  var length = arr.length;
  var result = [];
  if (length > 0) {
    while (length--) {
      result[length] = arr[length];
    }
  }
  return result;
};

Function.prototype.bind = function() {
  if (arguments.length < 2 && !arguments[0]) {
    return this;
  }
  var __method = this;
  var args = Fsz.$Array(arguments);
  var object = args.shift();
  return function() {
    return __method.apply(object, args.concat(Fsz.$Array(arguments)));
  };
}
/**
 * Class Methods.
 * @author juniac, hamdalf(IE9 patch)
 * @date 2010-10-21
 */
Fsz.Class = function() {
  var parentClass = null,
    definition = null;
  var arg = Fsz.$Array(arguments);
  if (Fsz.datatype.getType(arg[0]) == 'function') {
    parentClass = arg.shift();
  }
  if (Fsz.isObject(arg[0])) {
    definition = arg[0];
  }

  var newClass = function() {
      if (this.initialize != undefined) {
        this.initialize.apply(this, arguments);
      }
    };

  if (parentClass) {
    var t = new parentClass(arguments);
    for (var key in t) {
      newClass.prototype[key] = t[key];
    }
    newClass.parent = parentClass;
  }

  for (var prop in definition) {
    newClass.prototype[prop] = definition[prop];
  }


  if (!newClass.prototype.initialize) {
    newClass.prototype.initialize = Fsz.emptyFunction;
  }

  newClass.prototype.extend = Fsz.extend;
  newClass.prototype.constructor = newClass;
  return newClass;

};



/**
 * Browser Object Model.
 * IE를 제외한 브라우저의 경우에는 값을 얻을때 userAgent를 파싱한다.
 * 많이 사용하는 함수들중 userAgent 파싱이 필요 없는 부분은 따로 메쏘드 선언해서 속도면에서 최적화 시킴.
 * @author juniac, hamdalf(IE9 patch)
 * @date 2010-10-21
 */
Fsz.getBrowserInfo = function() {
  var name = null;
  var version = null;
  var browserData = [{
    name: 'Explorer',
    parseTarget: navigator.userAgent,
    refer: 'MSIE',
    versionRegExp: /(?:MSIE) ([0-9.]+)/
  }, {
    name: 'Firefox',
    parseTarget: navigator.userAgent,
    refer: 'Firefox',
    versionRegExp: /(?:Firefox)\/([0-9.]+)/

  }, {
    name: 'Chrome',
    parseTarget: navigator.userAgent,
    refer: 'Chrome',
    versionRegExp: /(?:Chrome)\/([0-9.]+)/
  }, {
    name: 'Opera',
    parseTarget: navigator.userAgent,
    refer: 'Opera',
    versionRegExp: /(?:Opera)\/([0-9.]+)/
  }, {
    name: 'Safari',
    parseTarget: navigator.vendor,
    refer: 'Apple',
    versionRegExp: /(?:Version)\/([0-9.]+)/
  }];
  var osData = [{
    name: 'Windows',
    refer: 'Win'
  }, {
    name: 'Mac',
    refer: 'Mac'
  }, {
    name: 'Linux',
    refer: 'Linux'
  }];

  var browserCount = browserData.length;
  try {
    for (var i = 0; i < browserCount; i++) {
      if (browserData[i].parseTarget.indexOf(browserData[i].refer) != -1) {
        name = browserData[i].name;
        version = navigator.userAgent.match(browserData[i].versionRegExp)[1];
      }
    }
  } catch (e) {}

  return {
    version: version,
    name: name,
    _version: version,
    _name: name

  };
};


/**
 * 기본 브라우져 정보만 따로 메쏘드로 가지고 있기.
 * isIE6, isIE7등 브라우저 버전정보가 있는 것은 브라우저 userAgent 파싱을 먼저 거친다.
 */
Fsz.browser = {
  isIE: function() {
    //return '\v' == 'v';
    return /MSIE/.test(navigator.userAgent);
  },
  isFF: function() {
    return /Firefox/.test(navigator.userAgent);
  },
  isSafari: function() {
    return /Apple.*Safari/.test(navigator.userAgent);
  },
  isOpera: function() {
    return /Opera/.test(navigator.userAgent);
  },
  isChrome: function() {
    return /Chrome/.test(navigator.userAgent);
  },
  isMobileSafari: function() {
    return /Apple.*Mobile.*Safari/.test(navigator.userAgent);
  },
  isIE6: function() {
    return /MSIE 6/.test(navigator.userAgent);
  },
  isIE7: function() {
    return /MSIE 7/.test(navigator.userAgent);
  },
  isIE8: function() {
    return /MSIE 8/.test(navigator.userAgent);
  },
  isIE9: function() {
    return /MSIE 9/.test(navigator.userAgent);
  },
  isFF2: function() {
    return /Firefox\/2/.test(navigator.userAgent);
  },
  isFF3: function() {
    return /Firefox\/3/.test(navigator.userAgent);
  },
  isIE9Under: function() {
    if (Fsz.browser.isIE() === true && Fsz.browser.isIE9() === false) {
      return true;
    } else {
      return false;
    }
  },
  isStrict: function() {
    return document.compatMode == 'CSS1Compat';
  },
  isHTTPS: function() {
    return window.location.href.toLowerCase().indexof('https') === 0;
  },
  getInfo: function() {
    if (Fsz.browser._version == undefined) {
      Fsz.browser.extend(Fsz.getBrowserInfo());
    }
  },
  extend: Fsz.extend
};

Fsz.getBrowser = function() {
  if (Fsz.browser._version == undefined) {
    Fsz.extend(Fsz.browser, Fsz.getBrowserInfo());
  }
};

Fsz.getBrowser();

/**
 * Platform method.
 * @author juniac, hamdalf(IE9 patch)
 * @date 2010-10-21
 */
Fsz.os = {
  isWindows: function() {
    return /Windows/.test(navigator.userAgent);
  },
  isLinux: function() {
    return /Linux/.test(navigator.userAgent);
  },
  isOSX: function() {
    return /Macintosh/.test(navigator.userAgent);
  }
};

Fsz.getOSInfo = function() {
  var name = null;
  var version = null;

  var osData = [{
    name: 'Windows',
    version: '2000',
    platform: "Windows",
    versionRegExp: /Windows NT 5.0/
  }, {
    name: 'Windows',
    version: 'XP',
    platform: "Windows",
    versionRegExp: /Windows NT 5.1/
  }, {
    name: 'Windows',
    version: 'VISTA',
    platform: "Windows",
    versionRegExp: /Windows NT 6.0/
  }, {
    name: 'Windows',
    version: 7,
    platform: "Windows",
    versionRegExp: /Windows NT 7.0/
  }, {
    name: 'OSX',
    version: '',
    platform: "Macintosh",
    versionRegExp: /(?:OS X )([0-9._]+)/
  }, {
    name: 'Linux',
    version: '',
    platform: "Linux",
    versionRegExp: /Linux/
  }];
  var osCount = osData.length;
  try {
    for (var i = 0; i < osCount; i++) {
      if (name == null && navigator.userAgent.indexOf(osData[i].platform) != -1) {
        name = osData[i].name;
      }
      switch (name) {
      case 'Windows':
        if (osData[i].versionRegExp.test(navigator.userAgent)) {
          version = osData[i].version;
        }
        break;
      case 'OSX':
        version = navigator.userAgent.match(osData[i].versionRegExp)[1];
        break;
      case 'Linux':
        break;
      }
    }
  } catch (e) {}
  return {
    name: name,
    version: version,
    _name: name,
    _version: version
  };
};

Fsz.getOS = function() {
  if (Fsz.os._name == undefined) {
    Fsz.extend(Fsz.os, Fsz.getOSInfo());
  }
};
Fsz.getOS();

/**
 
 * Browser Viewport Method.
 * @author juniac
 * @date 2008-02-04
 */

Fsz.viewport = {
  getWidth: function() {
    return window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
  },
  getHeight: function() {
    return window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
  },
  getDimention: function() {
    return {
      width: window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth,
      height: window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight
    };
  },
  getAvailableWidth: function() {
    return window.screen.availWidth;
  },
  getAvailableHeight: function() {
    return window.screen.availHeight;
  },
  getAvailableDimention: function() {
    return {
      width: window.screen.availWidth,
      height: window.screen.availHeight
    };
  },
  getContentsWidth: function() {
    return document.body.scrollWidth;
  },
  getContentsHeight: function() {
    return document.body.scrollHeight;
  }

};

Fsz.window = {
  getScreenTop: function() {
    return window.screenY || window.screenTop;
  },
  getScreenLeft: function() {
    return window.screenX || window.screenLeft;
  },
  getScreenPosition: function() {
    return {
      top: window.screenY || window.screenTop,
      left: window.screenX || window.screenLeft
    };
  }
};

Fsz.extend({
  getScrollTop: function() {
    return window.pageXOffset || (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop;
  },
  getScrollLeft: function() {
    return window.pageXOffset || (document.documentElement && document.documentElement.scrollLeft) || document.body.scrollLeft;
  },
  getScroll: function() {
    return {
      top: this.getScrollTop(),
      left: this.getScrollLeft()
    };
  }
});
/**
 * plugin Method.
 * @author juniac, hamdalf(IE9 patch)
 * @date 2010-10-21
 */
Fsz.extend({
  hasFlashPlayer: function() {
    var plugin = navigator.plugins;
    var mimeType = navigator.mimeTypes;
    var installed = false;
    if (Fsz.browser.isIE9Under() == false && plugin) {
      if (plugin['Shockwave Flash']) {
        installed = true;
      } else if (plugin['Shockwave Flash 2.0']) {
        installed = true;
      }
    } else {
      if (Fsz.browser.isIE9Under() && mimeType) {
        if (mimeType['application/x-shockwave-flash'] && mimeType['application/x-shockwave-flash'].enabledPlugin) {
          installed = true;
        }
      }
    }
    return installed;

  },
  hasSilverlight: function() {
    var installed = false;
    if (Fsz.browser.isIE() == true) {
      try {
        var silverlight = new ActiveXObject("AgControl.AgControl")
        installed = true;
      } catch (e) {}
    } else {
      var plugin = navigator.plugins;
      if (plugin['Silverlight Plug-in']) {
        installed = true;
      }
    }
    return installed;
  }
});







Fsz.datatype = {
  getType: function(target) {
    target = this.detectTarget(target);
    var type = this.getStrictType(target);
    var result = type.replace(/\[|\]|object /g, '').toLowerCase();
    return result;
  },
  dataType: {
    'function': '[object Function]',
    'object': '[object Object]',
    'number': '[object Number]',
    'string': '[object String]',
    'array': '[object Array]',
    'date': '[object Date]'
  },
  getStrictType: function(t) {
    t = this.detectTarget(t);
    return Object.prototype.toString.call(t);
  },
  isFunction: function(f) {
    f = this.detectTarget(f);
    //function 는 왜지? IE에서 되지 않음. 이렇게 스트링으로 한번 감싸주어야함
    return this.dataType['function'] === this.getStrictType(f);
  },
  isObject: function(o) {
    o = this.detectTarget(o);
    return this.dataType.object === this.getStrictType(o);
  },
  isNumber: function(n) {
    n = this.detectTarget(n);
    return this.dataType.number === this.getStrictType(n);
  },
  isString: function(s) {
    s = this.detectTarget(s);
    return this.dataType.string === this.getStrictType(s);
  },
  isArray: function(a) {
    a = this.detectTarget(a);
    return this.dataType.array === this.getStrictType(a);
  },
  isHash: function(a) {
    a = this.detectTarget(a);
    return a instanceof Fsz.Hash;
  },
  isDate: function(d) {
    d = this.detectTarget(d);
    return this.dataType.date === this.getStrictType(d);
  },
  detectTarget: function(t) {
    if (t == undefined) {
      return this;
    } else {
      return t;
    }
  }
};
Fsz.extend(Fsz.datatype);



Fsz.Array = {

  each: function(handler) {
    var index = 0;
    var callback = function(value) {
        handler.call(this, value);
      }

    for (var i = 0; i < this.length; i++) {
      callback(this[i]);
    }
  },
  iterator: function() {
    var arr = this;
    var index = 0;
    if (this.length == 0 || this.length == undefined) {
      return {
        value: null,
        hasNext: function() {
          return false;
        },
        next: function() {
          return null;
        },
        current: function() {
          return null;
        }
      };
    }
    //this.index = 0;
    var hasNext = function() {
        if (arr[index] != undefined) {
          return true;
        } else {
          return false;
        }
      };

    var next = function() {
        return arr[index++];
      };
    var current = function() {
        if (index - 1 < 0) {
          return undefined;
        } else {
          return arr[index - 1];
        }
      };
    return {
      index: index,
      value: arr,
      hasNext: hasNext,
      next: next,
      current: current
    };

  },
  first: function() {
    if (this.length > 0) {
      return this[0];
    } else {
      return undefined;
    }
  },
  last: function() {
    if (this.length > 0) {
      return this[this.length - 1];
    } else {
      return undefined;
    }
  },
  /**
   * TODO: Function find 2차 배열 이상일때 배열간 비교 처리해야함.
   */
  find: function(f) {
    var l = this.length;
    for (var i = 0; i < l; i++) {
      if (f == this[i]) {
        return this[i];
      }
    }
    return false;
  },
  truncate: function() {
    this.length = 0;
  },
  clone: function() {
    return Array.prototype.slice.call(this, 0);
  },

  /**
   * 배열 비교.
   */
  equal: function(target) {
    var l = this.length;
    console.log(l);
    var targetLength = targetLength;
    if (l != targetLength) {
      return false;
    }
    for (var i = 0; i < l; i++) {

    }


  }
};

Fsz.extendPrototype(Array, Fsz.datatype);
Fsz.extendPrototype(Array, Fsz.Array);

Fsz.Number = {
  'padding': function() {
    var t = arguments[0] || (this.isNumber() && this) || 0;
    if (arguments[1] != undefined && arguments[1] > 0) {
      var dummy = arguments[1];
    } else {
      dummy = 0;
    }
    var paddingCount = t - (this.toString().length);
    var buffer = '';
    for (var i = 0; i < paddingCount; i++) {
      buffer += dummy.toString();
    }
    return buffer += this.toString();
  },
  toCurrency: function() {
    var num = arguments[0] || (this.isNumber() && this) || undefined;
    if (num == undefined) {
      return false;
    }
    var separation = num.toString().split('.');
    var fixedNumber = separation[0];
    var decimal = separation.length > 1 ? '.' + separation[1] : '';
    var unit = /(\d+)(\d{3})/;
    while (unit.test(fixedNumber)) {
      fixedNumber = fixedNumber.replace(unit, '$1' + ',' + '$2');
    }
    return fixedNumber + decimal;
  },
  toPixel: function() {
    return this + 'px';
  },
  px: function() {
    return this + 'px';
  },
  toHex: function() {
    var value = this;
    if (value == null) {
      return '00';
    } else if (value < 10) {
      return value.padding(2);
    }
    value = parseInt(value);
    value = Math.max(0, value);
    value = Math.min(255, value);
    value = Math.round(value);
    return "0123456789ABCDEF".charAt((value - value % 16) / 16) + "0123456789ABCDEF".charAt(value % 16);

  },
  inArray: function(array) {
    var arrayLength = array.length;
    for (var i = 0; i < arrayLength; i++) {
      var type = Fsz.datatype.getType(array[i]);
      if (type == 'number' || type == 'boolean' || type == 'string') {
        if (array[i].toString() == this.toString()) {
          return true;
        }
      }
    }
    return false;

  },
  equal: function(number) {
    return this == number;
  }
};
Fsz.extendPrototype(Number, Fsz.Number);
Fsz.extendPrototype(Number, Fsz.datatype);

Fsz.String = {
  trim: function() {
    return (arguments[0] || (Fsz.datatype.isString(this) && this) || "").replace(/^\s+|\s+$/g, "");
  },
  rtrim: function() {
    return (arguments[0] || (Fsz.datatype.isString(this) && this) || "").replace(/\s+$/, "");
  },
  ltrim: function() {
    return (arguments[0] || (Fsz.datatype.isString(this) && this) || "").replace(/^\s+/, "");
  },
  stripTag: function() {
    return (arguments[0] || (Fsz.datatype.isString(this) && this) || "").replace(/<([^<>\s]*)(\s[^<>]*)?>/g, "");
  },
  find: function(t) {
    if (Fsz.datatype.isString(t) || Fsz.datatype.isNumber(t)) {
      return this.indexOf(t) > -1;
    } else if (Fsz.datatype.getType(t) == 'regexp') {
      return t.test(this);
    } else {
      return false;
    }
  },
  extractNumber: function() {
    var string = (arguments[0] || (this.isString() && this) || "");
    var number = string.match(/[0-9]/g);
    if (number.length > 0) {
      return parseInt(number.join(''), 10);
    } else {
      return null;
    }

  },
  parseQuery: function() {
    var url = arguments[0] || (this.isString() && this) || "";
    var query = url.substring((url.indexOf('?') + 1));
    if (url == "" || query == "") {
      return undefined;
    }
    var pair = query.split('&'),
      pairLength = pair.length;
    var buffer = {};
    for (var i = 0; i < pairLength; i++) {
      var arr = pair[i].split('=');
      if (arr.length > 0) {
        buffer[arr[0]] = arr[1];
      }
    }
    return buffer;
  },
  toNumber: function() {
    return parseInt((arguments[0] || (this.isString() && this) || ""), 10);
  },
  toDecimal: function() {
    return parseInt((arguments[0] || (this.isString() && this) || ""), 16);
  },
  RGBtoHex: function() {
    var str = arguments[0] || (this.isString() && this) || '';
    if (str.indexOf('rgb') == -1) {
      return str;
    }
    str = str.replace('rgb(', '');
    str = str.replace(')', '');
    str = str.replace(' ', '');
    str = str.replace(' ', '');
    var tmp = str.split(',');
    var hexString = parseInt(tmp[0]).toHex() + parseInt(tmp[1]).toHex() + parseInt(tmp[2]).toHex();
    return hexString;
  },
  HexToRGB: function() {
    var str = arguments[0] || (this.isString() && this) || '';
    str = str.replace('#');
    var RGBObject = {};
    RGBObject.R = parseInt(str.substring(0, 2), 16);
    RGBObject.G = parseInt(str.substring(2, 4), 16);
    RGBObject.B = parseInt(str.substring(4, 6), 16);
    return RGBObject;
  },
  inArray: function(array) {
    var arrayLength = array.length;
    for (var i = 0; i < arrayLength; i++) {
      var type = Fsz.datatype.getType(array[i]);
      if (type == 'number' || type == 'boolean' || type == 'string') {
        if (array[i].toString() == this.toString()) {
          return true;
        }
      }
    }
    return false;

  },
  decodeJSON: function() {
    return Fsz.json.decode(this);
  },
  equal: function() {
    return this == arguments[0];
  }
};
Fsz.extendPrototype(String, Fsz.datatype);
Fsz.extendPrototype(String, Fsz.String);
Fsz.Hash = function(hash) {
  var data = hash;

  var each = function(handler) {
      var callback = function(key, value) {
          handler.call(this, [key, value]);
        }
      for (var v in this.data) {
        if (this.data.propertyIsEnumerable(v)) {
          callback(v, this.data[v]);
        }
      }
    };

  return {
    data: data,
    each: each
  };

};


Fsz.Object = {
  equal: function(target) {
    for (var n in this) {
      if (this.hasOwnProperty(this[n])) {
        continue;
      }
      if (target[n]) {
        if (false == this[n].equal(target[n])) {
          return false;
        }
      } else {
        return false;
      }
    }
    return true;
  }
};


//Fsz.extendPrototype(Object, Fsz.Object);
//Fsz.extendPrototype(Object, Fsz.datatype);
Fsz.datatype.json = {
  encode: function(wannaBeJSON) {
    var datatype = Fsz.datatype.getType(wannaBeJSON);
    switch (datatype) {
    case 'undefiend':
    case 'function':
      return '';
      break;
    case 'number':
      return this.encodeNumber(wannaBeJSON);
      break;
    case 'string':
      return this.encodeString(wannaBeJSON);
      break;
    case 'boolean':
      return this.encodeBoolean(wannaBeJSON);
      break;
    case 'array':
      return this.encodeArray(wannaBeJSON);
      break;
    case 'object':
      return this.encodeObject(wannaBeJSON);
      break;
    }

  },
  decode: function(jsonString) {
    if (!jsonString || !(Fsz.isString(jsonString) || Fsz.isNumber(jsonString))) {
      return null;
    }
    try {
      return eval('(' + jsonString + ')');
    } catch (e) {}
  },

  encodeNumber: function(number) {
    return number;
  },
  encodeString: function(string) {
    var map = {
      '\b': '\\b',
      '\t': '\\t',
      '\n': '\\n',
      '\f': '\\f',
      '\r': '\\r',
      '"': '\\"',
      '\\': '\\\\',
      '\-': '\-'
    };
    var r = /["\\\x00-\x1f\x7f\-\x9f]/g;
    if (r.test(string)) {
      string = string.replace(r, function(p) {
        var c = map[p];
        if (c) {
          return c;
        } else {}
      });
    }
    return '"' + string + '"';
  },
  encodeBoolean: function(bool) {
    return bool ? "true" : "false";
  },
  encodeArray: function(array) {
    var arrayLength = array.length;
    var jsonArray = [];
    for (var i = 0; i < arrayLength; i++) {
      if (Fsz.datatype.getType(array[i]) != 'function') {
        jsonArray.push(Fsz.json.encode(array[i]));
      }
    }
    return "[" + jsonArray.join(', ') + "]";
  },
  encodeObject: function(object) {
    var jsonObject = [];
    var i = 0;
    for (var k in object) {
      if (Fsz.datatype.getType(object[k]) != 'function') {
        /**
         * @TODO 
         * object에 binding 된 오브젝트나 function을 구분할 수 있는 좋은 방법을 찾아보기
         */
        if (k.toString().inArray(['dataType'])) {
          continue;
        }
        if (object[k] == null) {
          jsonObject.push(this.encodeString(k) + ':' + 'null');
        } else {
          jsonObject.push(this.encodeString(k) + ':' + Fsz.json.encode(object[k]));
        }
      }
    }
    return "{" + jsonObject.join(', ') + "}";
  }
};

Fsz.json = Fsz.datatype.json;
/**
 * Event Object
 * @alias Fsz.Event
 * @author hamdalf
 * @date 2010-10-21
 */
Fsz.Event = {
  observers: false,
  _observeAndCache: function(element, name, observer, useCapture) {
    if (!this.observers) this.observers = [];

    try {
      if (Fsz.browser.isIE() == false) {
        this.observers.push([element, name, observer, useCapture]);
        element.addEventListener(name, observer, useCapture);
      } else if (element.attachEvent) {
        this.observers.push([element, name, observer, useCapture]);
        element.attachEvent('on' + name, observer);
      }
    } catch (e) {}
  },
  /**
   * Unregisters all event handlers registered by observe(). Autometically binded by document's unload event.
   */
  unloadCache: function() {
    if (!Fsz.Event.observers) return;
    for (var i = 0, length = Fsz.Event.observers.length; i < length; i++) {
      Fsz.Event.stopObserving.apply(this, Fsz.Event.observers[i]);
      Fsz.Event.observers[i][0] = null;
    }
    Fsz.Event.observers = false;
  },
  /**
   * Returns the DOM element on which the event occurred.
   * @param {Object} event
   * @return (DOM element)
   */
  element: function(event) {
    event = Fsz.Event.fix(event);
    return Fsz.$(event.target || event.srcElement);
  },
  /**
   * Registers an event handler on a DOM element.
   * @param {String} element
   * @param {String} name
   * @param {Function} observer
   * @param {Bool} useCapture
   */
  observe: function(element, name, observer, useCapture) {
    if (element == window || element == document) {
      element = element;
    } else {
      element = Fsz.$(element);
    }
    useCapture = useCapture || false;

    if (name == 'keypress' && (navigator.appVersion.match(/Konqueror|Safari|KHTML/) || element.attachEvent)) {
      name = 'keydown';
    }
    Fsz.Event._observeAndCache(element, name, observer, useCapture);
  },
  /**
   * Unregisters one or more event handlers.
   * @param {String} element
   * @param {String} name
   * @param {Function} observer
   * @param {Bool} useCapture
   */
  stopObserving: function(element, name, observer, useCapture) {
    element = Fsz.$(element);
    useCapture = useCapture || false;
    if (name == 'keypress' && (navigator.appVersion.match(/Konqueror|Safari|KHTML/) || element.attachEvent)) {
      name = 'keydown';
    }
    if (element.removeEventListener) {
      element.removeEventListener(name, observer, useCapture);
    } else if (element.detachEvent) {
      try {
        element.detachEvent('on' + name, observer);
      } catch (e) {}
    }
  },
  /**
   * Determines whether a event-occurring-mouse button is left.
   * @param {Object} event
   * @return (Bool)
   */
  isLeftClick: function(event) {
    event = Fsz.Event.fix(event);
    return (((event.which) && (event.which == 1)) || ((event.button) && (event.button == 1)));
  },
  isRightClick: function(event) {
    event = Fsz.Event.fix(event);
    return (((event.which) && (event.which == 2)) || ((event.button) && (event.button == 2)));
  },
  /**
   * Returns the absolute horizontal position for a mouse event.
   * @param {Object} event
   * @return (Number) mouse's horizontal position
   */
  pointerX: function(event) {
    var event = this.fix(event);
    return event.pageX || (event.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft));
  },
  /**
   * Returns the absolute vertical position for a mouse event.
   * @param {Object} event
   * @return (Number) mouse's vertical position
   */
  pointerY: function(event) {
    var event = this.fix(event);
    return event.pageY || (event.clientY + (document.documentElement.scrollTop || document.body.scrollTop));
  },
  /**
   * Stops the event's propagation and prevents its default action from beging triggered eventually. 
   * @param {Object} event
   */
  stop: function(event) {
    var event = Fsz.Event.fix(event);
    if (Fsz.browser.isIE() == false) {
      event.stopPropagation();
      event.preventDefault();
      //event.cancelable = false;
    } else {
      event.cancelBubble = true;
      event.returnValue = false;
    }
  },
  fix: function(event) {
    return event || window.event;
  }
}

if (!window.Event) {
  var Event = {};
}

Fsz.extend(Event, Fsz.Event);

/* prevent memory leaks in IE */
if (Fsz.browser.isIE9Under()) {
  Fsz.Event.observe(window, 'unload', Fsz.Event.unloadCache, false);
}


/*!
 * Sizzle CSS Selector Engine - v1.0
 *  Copyright 2009, The Dojo Foundation
 *  Released under the MIT, BSD, and GPL Licenses.
 *  More information: http://sizzlejs.com/
 */ (function() {

  var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,
    done = 0,
    toString = Object.prototype.toString,
    hasDuplicate = false;

  var Sizzle = function(selector, context, results, seed) {
      results = results || [];
      var origContext = context = context || document;

      if (context.nodeType !== 1 && context.nodeType !== 9) {
        return [];
      }

      if (!selector || typeof selector !== "string") {
        return results;
      }

      var parts = [],
        m, set, checkSet, check, mode, extra, prune = true,
        contextXML = isXML(context);

      // Reset the position of the chunker regexp (start from head)
      chunker.lastIndex = 0;

      while ((m = chunker.exec(selector)) !== null) {
        parts.push(m[1]);

        if (m[2]) {
          extra = RegExp.rightContext;
          break;
        }
      }

      if (parts.length > 1 && origPOS.exec(selector)) {
        if (parts.length === 2 && Expr.relative[parts[0]]) {
          set = posProcess(parts[0] + parts[1], context);
        } else {
          set = Expr.relative[parts[0]] ? [context] : Sizzle(parts.shift(), context);

          while (parts.length) {
            selector = parts.shift();

            if (Expr.relative[selector]) selector += parts.shift();

            set = posProcess(selector, set);
          }
        }
      } else {
        // Take a shortcut and set the context if the root selector is an ID
        // (but not if it'll be faster if the inner selector is an ID)
        if (!seed && parts.length > 1 && context.nodeType === 9 && !contextXML && Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1])) {
          var ret = Sizzle.find(parts.shift(), context, contextXML);
          context = ret.expr ? Sizzle.filter(ret.expr, ret.set)[0] : ret.set[0];
        }

        if (context) {
          var ret = seed ? {
            expr: parts.pop(),
            set: makeArray(seed)
          } : Sizzle.find(parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML);
          set = ret.expr ? Sizzle.filter(ret.expr, ret.set) : ret.set;

          if (parts.length > 0) {
            checkSet = makeArray(set);
          } else {
            prune = false;
          }

          while (parts.length) {
            var cur = parts.pop(),
              pop = cur;

            if (!Expr.relative[cur]) {
              cur = "";
            } else {
              pop = parts.pop();
            }

            if (pop == null) {
              pop = context;
            }

            Expr.relative[cur](checkSet, pop, contextXML);
          }
        } else {
          checkSet = parts = [];
        }
      }

      if (!checkSet) {
        checkSet = set;
      }

      if (!checkSet) {
        throw "Syntax error, unrecognized expression: " + (cur || selector);
      }

      if (toString.call(checkSet) === "[object Array]") {
        if (!prune) {
          results.push.apply(results, checkSet);
        } else if (context && context.nodeType === 1) {
          for (var i = 0; checkSet[i] != null; i++) {
            if (checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i]))) {
              results.push(set[i]);
            }
          }
        } else {
          for (var i = 0; checkSet[i] != null; i++) {
            if (checkSet[i] && checkSet[i].nodeType === 1) {
              results.push(set[i]);
            }
          }
        }
      } else {
        makeArray(checkSet, results);
      }

      if (extra) {
        Sizzle(extra, origContext, results, seed);
        Sizzle.uniqueSort(results);
      }

      return results;
    };

  Sizzle.uniqueSort = function(results) {
    if (sortOrder) {
      hasDuplicate = false;
      results.sort(sortOrder);

      if (hasDuplicate) {
        for (var i = 1; i < results.length; i++) {
          if (results[i] === results[i - 1]) {
            results.splice(i--, 1);
          }
        }
      }
    }
  };

  Sizzle.matches = function(expr, set) {
    return Sizzle(expr, null, null, set);
  };

  Sizzle.find = function(expr, context, isXML) {
    var set, match;

    if (!expr) {
      return [];
    }

    for (var i = 0, l = Expr.order.length; i < l; i++) {
      var type = Expr.order[i],
        match;

      if ((match = Expr.match[type].exec(expr))) {
        var left = RegExp.leftContext;

        if (left.substr(left.length - 1) !== "\\") {
          match[1] = (match[1] || "").replace(/\\/g, "");
          set = Expr.find[type](match, context, isXML);
          if (set != null) {
            expr = expr.replace(Expr.match[type], "");
            break;
          }
        }
      }
    }

    if (!set) {
      set = context.getElementsByTagName("*");
    }

    return {
      set: set,
      expr: expr
    };
  };

  Sizzle.filter = function(expr, set, inplace, not) {
    var old = expr,
      result = [],
      curLoop = set,
      match, anyFound, isXMLFilter = set && set[0] && isXML(set[0]);

    while (expr && set.length) {
      for (var type in Expr.filter) {
        if ((match = Expr.match[type].exec(expr)) != null) {
          var filter = Expr.filter[type],
            found, item;
          anyFound = false;

          if (curLoop == result) {
            result = [];
          }

          if (Expr.preFilter[type]) {
            match = Expr.preFilter[type](match, curLoop, inplace, result, not, isXMLFilter);

            if (!match) {
              anyFound = found = true;
            } else if (match === true) {
              continue;
            }
          }

          if (match) {
            for (var i = 0;
            (item = curLoop[i]) != null; i++) {
              if (item) {
                found = filter(item, match, i, curLoop);
                var pass = not ^ !! found;

                if (inplace && found != null) {
                  if (pass) {
                    anyFound = true;
                  } else {
                    curLoop[i] = false;
                  }
                } else if (pass) {
                  result.push(item);
                  anyFound = true;
                }
              }
            }
          }

          if (found !== undefined) {
            if (!inplace) {
              curLoop = result;
            }

            expr = expr.replace(Expr.match[type], "");

            if (!anyFound) {
              return [];
            }

            break;
          }
        }
      }

      // Improper expression
      if (expr == old) {
        if (anyFound == null) {
          throw "Syntax error, unrecognized expression: " + expr;
        } else {
          break;
        }
      }

      old = expr;
    }

    return curLoop;
  };

  var Expr = Sizzle.selectors = {
    order: ["ID", "NAME", "TAG"],
    match: {
      ID: /#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,
      CLASS: /\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,
      NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,
      ATTR: /\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
      TAG: /^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,
      CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
      POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
      PSEUDO: /:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/
    },
    attrMap: {
      "class": "className",
      "for": "htmlFor"
    },
    attrHandle: {
      href: function(elem) {
        return elem.getAttribute("href");
      }
    },
    relative: {
      "+": function(checkSet, part, isXML) {
        var isPartStr = typeof part === "string",
          isTag = isPartStr && !/\W/.test(part),
          isPartStrNotTag = isPartStr && !isTag;

        if (isTag && !isXML) {
          part = part.toUpperCase();
        }

        for (var i = 0, l = checkSet.length, elem; i < l; i++) {
          if ((elem = checkSet[i])) {
            while ((elem = elem.previousSibling) && elem.nodeType !== 1) {}

            checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ? elem || false : elem === part;
          }
        }

        if (isPartStrNotTag) {
          Sizzle.filter(part, checkSet, true);
        }
      },
      ">": function(checkSet, part, isXML) {
        var isPartStr = typeof part === "string";

        if (isPartStr && !/\W/.test(part)) {
          part = isXML ? part : part.toUpperCase();

          for (var i = 0, l = checkSet.length; i < l; i++) {
            var elem = checkSet[i];
            if (elem) {
              var parent = elem.parentNode;
              checkSet[i] = parent.nodeName === part ? parent : false;
            }
          }
        } else {
          for (var i = 0, l = checkSet.length; i < l; i++) {
            var elem = checkSet[i];
            if (elem) {
              checkSet[i] = isPartStr ? elem.parentNode : elem.parentNode === part;
            }
          }

          if (isPartStr) {
            Sizzle.filter(part, checkSet, true);
          }
        }
      },
      "": function(checkSet, part, isXML) {
        var doneName = done++,
          checkFn = dirCheck;

        if (!part.match(/\W/)) {
          var nodeCheck = part = isXML ? part : part.toUpperCase();
          checkFn = dirNodeCheck;
        }

        checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
      },
      "~": function(checkSet, part, isXML) {
        var doneName = done++,
          checkFn = dirCheck;

        if (typeof part === "string" && !part.match(/\W/)) {
          var nodeCheck = part = isXML ? part : part.toUpperCase();
          checkFn = dirNodeCheck;
        }

        checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
      }
    },
    find: {
      ID: function(match, context, isXML) {
        if (typeof context.getElementById !== "undefined" && !isXML) {
          var m = context.getElementById(match[1]);
          return m ? [m] : [];
        }
      },
      NAME: function(match, context, isXML) {
        if (typeof context.getElementsByName !== "undefined") {
          var ret = [],
            results = context.getElementsByName(match[1]);

          for (var i = 0, l = results.length; i < l; i++) {
            if (results[i].getAttribute("name") === match[1]) {
              ret.push(results[i]);
            }
          }

          return ret.length === 0 ? null : ret;
        }
      },
      TAG: function(match, context) {
        return context.getElementsByTagName(match[1]);
      }
    },
    preFilter: {
      CLASS: function(match, curLoop, inplace, result, not, isXML) {
        match = " " + match[1].replace(/\\/g, "") + " ";

        if (isXML) {
          return match;
        }

        for (var i = 0, elem;
        (elem = curLoop[i]) != null; i++) {
          if (elem) {
            if (not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0)) {
              if (!inplace) result.push(elem);
            } else if (inplace) {
              curLoop[i] = false;
            }
          }
        }

        return false;
      },
      ID: function(match) {
        return match[1].replace(/\\/g, "");
      },
      TAG: function(match, curLoop) {
        for (var i = 0; curLoop[i] === false; i++) {}
        return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase();
      },
      CHILD: function(match) {
        if (match[1] == "nth") {
          // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
          var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
          match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" || !/\D/.test(match[2]) && "0n+" + match[2] || match[2]);

          // calculate the numbers (first)n+(last) including if they are negative
          match[2] = (test[1] + (test[2] || 1)) - 0;
          match[3] = test[3] - 0;
        }

        // TODO: Move to normal caching system
        match[0] = done++;

        return match;
      },
      ATTR: function(match, curLoop, inplace, result, not, isXML) {
        var name = match[1].replace(/\\/g, "");

        if (!isXML && Expr.attrMap[name]) {
          match[1] = Expr.attrMap[name];
        }

        if (match[2] === "~=") {
          match[4] = " " + match[4] + " ";
        }

        return match;
      },
      PSEUDO: function(match, curLoop, inplace, result, not) {
        if (match[1] === "not") {
          // If we're dealing with a complex expression, or a simple one
          if (match[3].match(chunker).length > 1 || /^\w/.test(match[3])) {
            match[3] = Sizzle(match[3], null, null, curLoop);
          } else {
            var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
            if (!inplace) {
              result.push.apply(result, ret);
            }
            return false;
          }
        } else if (Expr.match.POS.test(match[0]) || Expr.match.CHILD.test(match[0])) {
          return true;
        }

        return match;
      },
      POS: function(match) {
        match.unshift(true);
        return match;
      }
    },
    filters: {
      enabled: function(elem) {
        return elem.disabled === false && elem.type !== "hidden";
      },
      disabled: function(elem) {
        return elem.disabled === true;
      },
      checked: function(elem) {
        return elem.checked === true;
      },
      selected: function(elem) {
        // Accessing this property makes selected-by-default
        // options in Safari work properly
        elem.parentNode.selectedIndex;
        return elem.selected === true;
      },
      parent: function(elem) {
        return !!elem.firstChild;
      },
      empty: function(elem) {
        return !elem.firstChild;
      },
      has: function(elem, i, match) {
        return !!Sizzle(match[3], elem).length;
      },
      header: function(elem) {
        return /h\d/i.test(elem.nodeName);
      },
      text: function(elem) {
        return "text" === elem.type;
      },
      radio: function(elem) {
        return "radio" === elem.type;
      },
      checkbox: function(elem) {
        return "checkbox" === elem.type;
      },
      file: function(elem) {
        return "file" === elem.type;
      },
      password: function(elem) {
        return "password" === elem.type;
      },
      submit: function(elem) {
        return "submit" === elem.type;
      },
      image: function(elem) {
        return "image" === elem.type;
      },
      reset: function(elem) {
        return "reset" === elem.type;
      },
      button: function(elem) {
        return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON";
      },
      input: function(elem) {
        return /input|select|textarea|button/i.test(elem.nodeName);
      }
    },
    setFilters: {
      first: function(elem, i) {
        return i === 0;
      },
      last: function(elem, i, match, array) {
        return i === array.length - 1;
      },
      even: function(elem, i) {
        return i % 2 === 0;
      },
      odd: function(elem, i) {
        return i % 2 === 1;
      },
      lt: function(elem, i, match) {
        return i < match[3] - 0;
      },
      gt: function(elem, i, match) {
        return i > match[3] - 0;
      },
      nth: function(elem, i, match) {
        return match[3] - 0 == i;
      },
      eq: function(elem, i, match) {
        return match[3] - 0 == i;
      }
    },
    filter: {
      PSEUDO: function(elem, match, i, array) {
        var name = match[1],
          filter = Expr.filters[name];

        if (filter) {
          return filter(elem, i, match, array);
        } else if (name === "contains") {
          return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0;
        } else if (name === "not") {
          var not = match[3];

          for (i = 0, l = not.length; i < l; i++) {
            if (not[i] === elem) {
              return false;
            }
          }

          return true;
        }
      },
      CHILD: function(elem, match) {
        var type = match[1],
          node = elem;
        switch (type) {
        case 'only':
        case 'first':
          while ((node = node.previousSibling)) {
            if (node.nodeType === 1) return false;
          }
          if (type == 'first') return true;
          node = elem;
        case 'last':
          while ((node = node.nextSibling)) {
            if (node.nodeType === 1) return false;
          }
          return true;
        case 'nth':
          var first = match[2],
            last = match[3];

          if (first == 1 && last == 0) {
            return true;
          }

          var doneName = match[0],
            parent = elem.parentNode;

          if (parent && (parent.sizcache !== doneName || !elem.nodeIndex)) {
            var count = 0;
            for (node = parent.firstChild; node; node = node.nextSibling) {
              if (node.nodeType === 1) {
                node.nodeIndex = ++count;
              }
            }
            parent.sizcache = doneName;
          }

          var diff = elem.nodeIndex - last;
          if (first == 0) {
            return diff == 0;
          } else {
            return (diff % first == 0 && diff / first >= 0);
          }
        }
      },
      ID: function(elem, match) {
        return elem.nodeType === 1 && elem.getAttribute("id") === match;
      },
      TAG: function(elem, match) {
        return (match === "*" && elem.nodeType === 1) || elem.nodeName === match;
      },
      CLASS: function(elem, match) {
        return (" " + (elem.className || elem.getAttribute("class")) + " ").indexOf(match) > -1;
      },
      ATTR: function(elem, match) {
        var name = match[1],
          result = Expr.attrHandle[name] ? Expr.attrHandle[name](elem) : elem[name] != null ? elem[name] : elem.getAttribute(name),
          value = result + "",
          type = match[2],
          check = match[4];

        return result == null ? type === "!=" : type === "=" ? value === check : type === "*=" ? value.indexOf(check) >= 0 : type === "~=" ? (" " + value + " ").indexOf(check) >= 0 : !check ? value && result !== false : type === "!=" ? value != check : type === "^=" ? value.indexOf(check) === 0 : type === "$=" ? value.substr(value.length - check.length) === check : type === "|=" ? value === check || value.substr(0, check.length + 1) === check + "-" : false;
      },
      POS: function(elem, match, i, array) {
        var name = match[2],
          filter = Expr.setFilters[name];

        if (filter) {
          return filter(elem, i, match, array);
        }
      }
    }
  };

  var origPOS = Expr.match.POS;

  for (var type in Expr.match) {
    Expr.match[type] = new RegExp(Expr.match[type].source + /(?![^\[]*\])(?![^\(]*\))/.source);
  }

  var makeArray = function(array, results) {
      array = Array.prototype.slice.call(array);

      if (results) {
        results.push.apply(results, array);
        return results;
      }

      return array;
    };

  // Perform a simple check to determine if the browser is capable of
  // converting a NodeList to an array using builtin methods.
  try {
    Array.prototype.slice.call(document.documentElement.childNodes);

    // Provide a fallback method if it does not work
  } catch (e) {
    makeArray = function(array, results) {
      var ret = results || [];

      if (toString.call(array) === "[object Array]") {
        Array.prototype.push.apply(ret, array);
      } else {
        if (typeof array.length === "number") {
          for (var i = 0, l = array.length; i < l; i++) {
            ret.push(array[i]);
          }
        } else {
          for (var i = 0; array[i]; i++) {
            ret.push(array[i]);
          }
        }
      }

      return ret;
    };
  }

  var sortOrder;

  if (document.documentElement.compareDocumentPosition) {
    sortOrder = function(a, b) {
      var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
      if (ret === 0) {
        hasDuplicate = true;
      }
      return ret;
    };
  } else if ("sourceIndex" in document.documentElement) {
    sortOrder = function(a, b) {
      var ret = a.sourceIndex - b.sourceIndex;
      if (ret === 0) {
        hasDuplicate = true;
      }
      return ret;
    };
  } else if (document.createRange) {
    sortOrder = function(a, b) {
      var aRange = a.ownerDocument.createRange(),
        bRange = b.ownerDocument.createRange();
      aRange.selectNode(a);
      aRange.collapse(true);
      bRange.selectNode(b);
      bRange.collapse(true);
      var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
      if (ret === 0) {
        hasDuplicate = true;
      }
      return ret;
    };
  }

  // Check to see if the browser returns elements by name when
  // querying by getElementById (and provide a workaround)
  (function() {
    // We're going to inject a fake input element with a specified name
    var form = document.createElement("div"),
      id = "script" + (new Date).getTime();
    form.innerHTML = "<a name='" + id + "'/>";

    // Inject it into the root element, check its status, and remove it quickly
    var root = document.documentElement;
    root.insertBefore(form, root.firstChild);

    // The workaround has to do additional checks after a getElementById
    // Which slows things down for other browsers (hence the branching)
    if ( !! document.getElementById(id)) {
      Expr.find.ID = function(match, context, isXML) {
        if (typeof context.getElementById !== "undefined" && !isXML) {
          var m = context.getElementById(match[1]);
          return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
        }
      };

      Expr.filter.ID = function(elem, match) {
        var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
        return elem.nodeType === 1 && node && node.nodeValue === match;
      };
    }

    root.removeChild(form);
    root = form = null; // release memory in IE
  })();

  (function() {
    // Check to see if the browser returns only elements
    // when doing getElementsByTagName("*")

    // Create a fake element
    var div = document.createElement("div");
    div.appendChild(document.createComment(""));

    // Make sure no comments are found
    if (div.getElementsByTagName("*").length > 0) {
      Expr.find.TAG = function(match, context) {
        var results = context.getElementsByTagName(match[1]);

        // Filter out possible comments
        if (match[1] === "*") {
          var tmp = [];

          for (var i = 0; results[i]; i++) {
            if (results[i].nodeType === 1) {
              tmp.push(results[i]);
            }
          }

          results = tmp;
        }

        return results;
      };
    }

    // Check to see if an attribute returns normalized href attributes
    div.innerHTML = "<a href='#'></a>";
    if (div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && div.firstChild.getAttribute("href") !== "#") {
      Expr.attrHandle.href = function(elem) {
        return elem.getAttribute("href", 2);
      };
    }

    div = null; // release memory in IE
  })();

  if (document.querySelectorAll)(function() {
    var oldSizzle = Sizzle,
      div = document.createElement("div");
    div.innerHTML = "<p class='TEST'></p>";

    // Safari can't handle uppercase or unicode characters when
    // in quirks mode.
    if (div.querySelectorAll && div.querySelectorAll(".TEST").length === 0) {
      return;
    }

    Sizzle = function(query, context, extra, seed) {
      context = context || document;

      // Only use querySelectorAll on non-XML documents
      // (ID selectors don't work in non-HTML documents)
      if (!seed && context.nodeType === 9 && !isXML(context)) {
        try {
          return makeArray(context.querySelectorAll(query), extra);
        } catch (e) {}
      }

      return oldSizzle(query, context, extra, seed);
    };

    for (var prop in oldSizzle) {
      Sizzle[prop] = oldSizzle[prop];
    }

    div = null; // release memory in IE
  })();

  if (document.getElementsByClassName && document.documentElement.getElementsByClassName)(function() {
    var div = document.createElement("div");
    div.innerHTML = "<div class='test e'></div><div class='test'></div>";

    // Opera can't find a second classname (in 9.6)
    if (div.getElementsByClassName("e").length === 0) return;

    // Safari caches class attributes, doesn't catch changes (in 3.2)
    div.lastChild.className = "e";

    if (div.getElementsByClassName("e").length === 1) return;

    Expr.order.splice(1, 0, "CLASS");
    Expr.find.CLASS = function(match, context, isXML) {
      if (typeof context.getElementsByClassName !== "undefined" && !isXML) {
        return context.getElementsByClassName(match[1]);
      }
    };

    div = null; // release memory in IE
  })();

  function dirNodeCheck(dir, cur, doneName, checkSet, nodeCheck, isXML) {
    var sibDir = dir == "previousSibling" && !isXML;
    for (var i = 0, l = checkSet.length; i < l; i++) {
      var elem = checkSet[i];
      if (elem) {
        if (sibDir && elem.nodeType === 1) {
          elem.sizcache = doneName;
          elem.sizset = i;
        }
        elem = elem[dir];
        var match = false;

        while (elem) {
          if (elem.sizcache === doneName) {
            match = checkSet[elem.sizset];
            break;
          }

          if (elem.nodeType === 1 && !isXML) {
            elem.sizcache = doneName;
            elem.sizset = i;
          }

          if (elem.nodeName === cur) {
            match = elem;
            break;
          }

          elem = elem[dir];
        }

        checkSet[i] = match;
      }
    }
  }

  function dirCheck(dir, cur, doneName, checkSet, nodeCheck, isXML) {
    var sibDir = dir == "previousSibling" && !isXML;
    for (var i = 0, l = checkSet.length; i < l; i++) {
      var elem = checkSet[i];
      if (elem) {
        if (sibDir && elem.nodeType === 1) {
          elem.sizcache = doneName;
          elem.sizset = i;
        }
        elem = elem[dir];
        var match = false;

        while (elem) {
          if (elem.sizcache === doneName) {
            match = checkSet[elem.sizset];
            break;
          }

          if (elem.nodeType === 1) {
            if (!isXML) {
              elem.sizcache = doneName;
              elem.sizset = i;
            }
            if (typeof cur !== "string") {
              if (elem === cur) {
                match = true;
                break;
              }

            } else if (Sizzle.filter(cur, [elem]).length > 0) {
              match = elem;
              break;
            }
          }

          elem = elem[dir];
        }

        checkSet[i] = match;
      }
    }
  }

  var contains = document.compareDocumentPosition ?
  function(a, b) {
    return a.compareDocumentPosition(b) & 16;
  } : function(a, b) {
    return a !== b && (a.contains ? a.contains(b) : true);
  };

  var isXML = function(elem) {
      return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" || !! elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML";
    };

  var posProcess = function(selector, context) {
      var tmpSet = [],
        later = "",
        match, root = context.nodeType ? [context] : context;

      // Position selectors must be done after the filter
      // And so must :not(positional) so we move all PSEUDOs to the end
      while ((match = Expr.match.PSEUDO.exec(selector))) {
        later += match[0];
        selector = selector.replace(Expr.match.PSEUDO, "");
      }

      selector = Expr.relative[selector] ? selector + "*" : selector;

      for (var i = 0, l = root.length; i < l; i++) {
        Sizzle(selector, root[i], tmpSet);
      }

      return Sizzle.filter(later, tmpSet);
    };

  // EXPOSE
  window.Sizzle = Sizzle;

})();
/**
 * DOM Methods.
 * @author juniac, hamdalf(IE9 patch)
 * @date 2010-10-21
 */
Fsz.dom = {
  filterElements: function(elements) {
    var returnElements = [],
      elementsLength = elements.length;
    for (var i = 0; i < elementsLength; i++) {
      if (elements[i].nodeType == 1 && /\S/.test(elements[i].nodeValue)) {
        returnElements.push(Fsz.$(elements[i]));
      }
    }
    if (returnElements.length > 0) {
      Fsz.extend(returnElements, Fsz.dom.Elements);
      var result = returnElements;
    } else {
      result = [];
    }
    return result;
  },

  getSiblings: function(property) {
    element = this;
    elements = [];
    while (element = element[property]) {
      if (element.nodeType == 1) {
        elements.push(element);
      }
    }
    return elements;
  },

  nextElements: function() {
    var elements = this.getSiblings('nextSibling');
    return elements;
  },

  previousElements: function() {
    var elements = this.getSiblings('previousSibling');
    return elements;
  },

  nextElement: function() {
    if (this.nextElements()[0]) {
      return Fsz.$(this.nextElements()[0]);
    } else {
      return null;
    }
  },

  previousElement: function() {
    if (this.previousElements()[0]) {
      return Fsz.$(this.previousElements()[0]);
    } else {
      return null
    }
  },

  parent: function() {
    var element = this;
    if (element.parentNode && element.parentNode.nodeType == 1) {
      return Fsz.$(element.parentNode);
    } else {
      undefined;
    }
  },

  parentElements: function() {
    elements = this.getSiblings('parentNode');
    return this.filterElements(elements);
  },

  childElements: function() {
    return this.filterElements(this.childNodes);
  },

  firstChildElement: function() {
    var first = this.firstChild;
    while (first && first.nodeType != 1) {
      first = first.nextSibling;
    }
    return Fsz.$(first);
  },

  lastChildElement: function() {
    var last = this.lastChild;
    while (last && last.nodeType != 1) {
      last = last.previousSibling
    }
    return Fsz.$(last);
  },

  first: this.firstChildElement,
  last: this.lastChildElement,
  next: this.nextElement,
  previous: this.previousElement,

  isChildOf: function(parent) {
    return parent == this.parent();
  },

  isParentOf: function(parent) {
    var element = this;
    var childElements = element.childElements();
    var childElementsLength = childElements.length;
    for (var i = 0; i < childElementsLength; i++) {
      if (childElements[i] == parent) {
        return true;
        break;
      }
    }
    return false;
  },

  get: function(attr) {
    var element = this;
    if (attr == 'className' || attr == 'class') {
      var result = element.className;
    } else {
      result = element.getAttribute(attr);
    }
    return result ? result : undefined;
  },

  set: function(attr, value) {
    var element = this;
    if (attr == 'className' || attr == 'class') {
      element.className = value;
    } else if (attr == 'for') {
      if (Fsz.browser.isIE9Under()) {
        element.setAttribute('htmlFor', value);
      } else {
        element.setAttribute('for', value);
      }
    } else {
      return element.setAttribute(attr, value);
    }
    return element;
  },

  removeAttr: function(attr) {
    var element = this;
    if (attr == 'class' || attr == 'className') {
      element.removeAttribute('class');
      element.removeAttribute('className');
      element.className = '';
    } else {
      element.removeAttribute(attr);
    }
    return element;

  },

  getClassName: function() {
    var classnames = this.className.toString().split(' ');
    var parsedClassNames = [];
    if (classnames.length > 0) {
      for (var i = 0; i < classnames.length; i++) {
        if (classnames[i].length > 0) {
          parsedClassNames.push(classnames[i]);
        }
      }
    }
    return parsedClassNames;
  },

  hasClassName: function(name) {
    var element = this;
    var classnames = element.getClassName();
    for (var i = 0; i < classnames.length; i++) {
      if (classnames[i] == name) {
        return true;
      }
    }
    return false;

  },

  addClassName: function(name) {
    if (this.hasClassName(name)) {
      return element;
    }
    var element = this;
    var classnames = element.getClassName();
    classnames.push(name);
    element.className = classnames.join(' ');
    return element;
  },

  removeClassName: function(name) {
    var element = this;
    var classnames = element.getClassName();
    var classnamesLength = classnames.length;
    var newclassnames = [];
    for (var i = 0; i < classnamesLength; i++) {
      if (classnames[i] != name) {
        newclassnames.push(classnames[i]);
      }
    }
    element.className = newclassnames.join(' ');
    return element;
  },

  swapClassName: function(before, after) {
    var element = this;
    var classnames = element.getClassName();
    var classnamesLength = classnames.length;
    for (var i = 0; i < classnamesLength; i++) {
      if (classnames[i] == before) {
        classnames[i] = after
      }
    }
    element.className = classnames.join(' ');
    return element;
  },

  isHTMLElement: function() {
    return this.nodeType == 1;
  },

  copy: function() {
    return this.cloneNode(true);
  },

  CSS: function() {},

  setCSS: function(css) {
    for (var c in css) {
      if (css[c].isString()) {
        this.style[c] = css[c];
      }
    }
    return element;
  },

  setStyle: function(attr, value) {
    var target = this;
    if (attr == 'float') {
      if (Fsz.browser.isIE9Under()) {
        target.style.styleFloat = value;
      } else {
        target.style.cssFloat = value;
      }
    } else {
      target.style[attr] = value;
    }
    return target;
  },

  getStyle: function(key) {
    var element = this;
    if (element.currentStyle) {
      var elementStyle = element.currentStyle[key] || null;
    } else {
      elementStyle = Fsz.d.defaultView.getComputedStyle(element, null).getPropertyValue(key) || null;
    }
    return elementStyle;

  },

  getCSS: function() {
    var element = this;
    var cssLength = element.style.length;
    var css = {};
    for (var i = 0; i < cssLength; i++) {
      var key = element.style[i];
      if ((element.style[key])) {
        css[key] = element.style[key];
        css[key] = Fsz.d.defaultView.getComputedStyle(element, null).getPropertyValue(key);
      }
    }
    return css;
  },

  getBackgroundColor: function() {
    var element = this;
    var bgColor;
    if (element.currentStyle) {
      bgColor = element.getStyle('backgroundColor');
      bgColor = bgColor.replace('#', '');
      if (bgColor.length == 3) {
        var newBgColor = bgColor[0] + bgColor[0] + bgColor[1] + bgColor[1] + bgColor[2] + bgColor[2];
        bgColor = newBgColor.toUpperCase();
      }
    } else {
      bgColor = element.getStyle('background-color');
      bgColor = bgColor.RGBtoHex();
    }
    return bgColor;

  },

  getLeft: function() {
    return this.offsetLeft;
  },

  getTop: function() {
    return this.offsetTop;
  },

  getOffsetTop: function() {
    var element = this;
    var t = 0;
    if (element.offsetParent) {
      while (element.offsetParent) {
        t += element.offsetTop;
        element = element.offsetParent;
      }
    }
    return t;
  },

  getOffsetLeft: function() {
    var element = this;
    var t = 0;
    if (element.offsetParent) {
      while (element.offsetParent) {
        t += element.offsetLeft;
        element = element.offsetParent;
      }
    }
    return t;
  },

  getWidth: function() {
    return this.getSize().width;
  },

  getHeight: function() {
    return this.getSize().height;
  },

  getSize: function() {
    var element = this;
    if (element.style.display != 'none' || element.style.display != null) {
      return {
        width: parseInt(element.offsetWidth || this.style.width, 10),
        height: parseInt(element.offsetHeight || this.style.height, 10)
      };
    }
    return {
      width: parseInt(element.clinetWidth || this.style.width, 10),
      height: parseInt(element.clientHeight || this.style.height, 10)
    };

  },

  setWidth: function(width) {
    var element = this;
    if (width.isNumber()) {
      width += 'px';
      element.style.width = width;
    } else if (/px/.test(width)) {
      element.style.width = width;
    }
    return element;
  },

  setHeight: function(height) {
    var element = this;
    if (height.isNumber()) {
      height += 'px';
      element.style.height = height;
    } else if (/px/.test(height)) {
      element.style.height = height;
    }
    return element;
  },

  update: function(contents) {
    var element = this;
    if (false == contents.isString() && contents.nodeType == 1) {
      element.replace(contents);
    } else {
      element.setHTML(contents);
    }
    return element;
  },

  isEmpty: function() {
    return this.firstChild == undefined;
  },

  truncate: function() {
    var element = this;
    element.innerHTML = '';
    return element;
  },

  getHTML: function() {
    var element = this;
    return element.innerHTML;
  },

  setHTML: function(html) {
    var element = this;
    element.innerHTML = html;
    return element;
  },

  replace: function(alternativeElement) {
    var target = this;
    target.parent().insertBefore(alternativeElement, target);
    target.parent().removeChild(target);
    return this;
  },

  addBefore: function(element) {
    var target = this;
    target.parentElement().insertBefore(element, target);
    return target;
  },

  addAfter: function(element) {
    var target = this;

  },

  setOpacity: function(opacity) {
    var target = this;
    if (Fsz.browser.isIE9Under()) {
      opacity = opacity;
      target.style.filter = 'alpha(opacity=' + opacity + ')';
    } else {
      target.style.opacity = opacity / 100;
    }
    return target;
  },

  getOpacity: function() {
    var target = this;
    var opacity;
    if (Fsz.browser.isIE9Under()) {
      opacity = target.style.filter.extractNumber();
    } else {
      opacity = target.style.opacity * 100;
    }
    return parseInt(opacity, 10);

  },

  $E: function(tag) {
    var newElement = Fsz.d.createElement(tag);
    newElement = Fsz.$(newElement);
    return newElement;
  },

  show: function() {
    var element = this;
    element.style.display = 'block';
    return element;
  },

  hide: function() {
    var element = this;
    element.style.display = 'none';
    return element;
  },

  toggle: function() {
    var element = this;
    if (element.style.display == 'none') {
      element.style.display = 'block';
    } else {
      element.style.display = 'none';
    }
    return element;
  },

  disableSelect: function() {
    var element = this;
    element.onmousedown = null;
  },

  Effect: function() {
    return this;
  },

  isLoaded: function() {
    return true;
  }
};


Fsz.dom.Elements = {
  iterate: function(handler) {
    this.each(handler);
  },
  removeAttr: function(attr) {
    this.iterate(function(e) {
      e.removeAttr(attr);
    });
    return this;
  },
  addClassName: function(classname) {
    this.iterate(function(e) {
      e.addClassName(classname);
    });
    return this;
  },
  removeClassName: function(classname) {
    this.iterate(function(e) {
      e.removeClassName(classname);
    });
    return this;
  },
  swapClassName: function(before, after) {
    this.iterate(function(e) {
      e.swapClassName(before, after);
    });
    return this;
  },
  setCSS: function(css) {
    this.iterate(function(e) {
      e.setCSS(css);
    });
    return this;
  },
  setWidth: function(width) {
    this.iterate(function(e) {
      e.setWidth(width);
    });
    return this;
  },
  setHeight: function(height) {
    this.iterate(function(e) {
      e.setHeight(height);
    });
    return this;
  },
  update: function(el) {
    this.iterate(function(e) {
      e.update(el);
    });
    return this;
  },
  truncate: function() {
    this.iterate(function(e) {
      e.truncate();
    });
    return this;
  },
  setHTML: function(html) {
    this.iterate(function(e) {
      e.setHTML(html);
    });
    return this;
  },
  show: function() {
    this.iterate(function(e) {
      e.show();
    });
    return this;
  },
  hide: function() {
    this.iterate(function(e) {
      e.hide();
    });
    return this;
  }
};


Fsz.selector = {
  $: function(id, parent) {
    var element;
    if (Fsz.datatype.isString(id)) {
      id = id.replace('#', '');
      element = document.getElementById(id);
    } else if (id && id.nodeType && (id.nodeType == 1 || id.nodeType == 9)) {
      element = id;
    }
    if ( !! element == false) {
      return false;
    }
    Fsz.extend(element, Fsz.dom);
    //if (element.nodeName.toUpperCase() == 'FORM') {
    //Fsz.extend(element, Fsz.form);
    //}
    element.$$ = function(selectorGroups) {
      return Fsz.$$(selectorGroups, '#' + element.id);
    }
    return element;
  },
  $$: function(selectorGroups, root, includeRoot, recursed, flat) {
    if (root) {
      root = Fsz.$(root);
    }
    //var selectedElements = peppy.query(selectorGroups, root, includeRoot, recursed, flat);
    var selectedElements = Sizzle(selectorGroups, root, includeRoot, recursed, flat);
    return Fsz.dom.filterElements(selectedElements);
  }
};
Fsz.$ = Fsz.selector.$;
Fsz.$$ = Fsz.selector.$$;
Fsz.$E = Fsz.dom.$E;
Fsz.getHTMLBody = function() {
  return Fsz.$(document.body);
};

var $ = ( !! $ == false) ? Fsz.$ : $;

Fsz.Effect = {
  opacity: function(element, opacity, duration, options) {
    var opacityOption = this.makeOptionForTweener(duration, options);
    opacityOption.opacity = opacity;
    element.setOpacity(100);
    Fsz.Tweener.addTween(element, opacityOption);

  },
  move: function(element, duration, options) {
    var moveOption = this.makeOptionForTweener(duration, options);
    if (options.left) {
      moveOption.left = options.left;
    }
    if (options.top) {
      moveOption.top = options.top;
    }
    moveOption.suffix = {
      left: 'px',
      top: 'px'
    };
    element.style.position = 'absolute';
    Fsz.Tweener.addTween(element.style, moveOption);
  },
  show: function(element, duration, options) {
    if (!duration) {
      element.show();
      return false;
    }
    element.setOpacity(0).show();
    var showOption = this.makeOptionForTweener(duration, options);
    showOption.opacity = 100;
    Fsz.Tweener.addTween(element, showOption);


  },
  hide: function(element, duration, options) {
    if (!duration) {
      element.hide();
      return false;
    }
    element.setOpacity(100).show();
    if (!options) {
      options = {};
    }
    var onComplete = options.onComplete ||
    function() {};
    options.onComplete = function() {
      onComplete();
      element.hide();
    };
    var showOption = this.makeOptionForTweener(duration, options);
    showOption.opacity = 0;
    Fsz.Tweener.addTween(element, showOption);
  },
  fold: function(element, duration, options) {
    var foldOption = this.makeOptionForTweener(duration || 1, options);
    element.setStyle('overflow', 'hidden');
    element.setStyle('height', element.getStyle('height'));
    foldOption.suffix = {
      height: 'px',
      width: 'px'
    };
    foldOption.height = 0;
    Fsz.Tweener.addTween(element.style, foldOption);

  },
  colorFadeOut: function(element, duration, options) {
    var fadeoutOption = this.makeOptionForTweener(duration || 1, options);
    var startColor = options.startColor ? options.startColor.replace('#', '') : null;
    var RGB = startColor.HexToRGB();
    fadeoutOption.startColorR = RGB.R;
    fadeoutOption.startColorG = RGB.G;
    fadeoutOption.startColorB = RGB.B;
    Fsz.Tweener.addTween(element, fadeoutOption);
  },
  expand: function(element, duration, options) {
    var expandOption = this.makeOptionForTweener(duration || 1, options);
    element.setStyle('overflow', 'hidden');
    expandOption.suffix = {
      height: 'px',
      width: 'px'
    };
    expandOption.height = parseInt(element.getStyle('height'), 10);
    element.setStyle('height', '0px');
    element.show();
    Fsz.Tweener.addTween(element.style, expandOption);
  },
  makeOptionForTweener: function(duration, options) {
    if (!options) {
      var options = {};
    }
    var optionForTweener = {
      time: duration || 1,
      transition: options.ease || 'linear',
      onComplete: options.onComplete ||
      function() {}
    };
    return optionForTweener;
  }
};

Fsz.Effect.Ease = {
  None: 'linear',
  'In': {
    Quad: 'easeInQuad',
    Cubic: 'easeInCubic',
    Quart: 'easeInQuart',
    Quint: 'easeInQuint',
    Sine: 'easeInSine',
    Expo: 'easeInExpo',
    Circ: 'easeInCirc',
    Elastic: 'easeInElastic',
    Back: 'easeInBack',
    Bounce: 'easeInBounce'
  },
  'Out': {
    Quad: 'easeOutQuad',
    Cubic: 'easeOutCubic',
    Quart: 'easeOutQuart',
    Quint: 'easeOutQuint',
    Sine: 'easeOutSine',
    Expo: 'easeOutExpo',
    Circ: 'easeOutCirc',
    Elastic: 'easeOutElastic',
    Back: 'easeOutBack',
    Bounce: 'easeOutBounce'

  },
  'InOut': {
    Quad: 'easeInOutQuad',
    Cubic: 'easeInOutCubic',
    Quart: 'easeInOutQuart',
    Quint: 'easeInOutQuint',
    Sine: 'easeInOutSine',
    Expo: 'easeInOutExpo',
    Circ: 'easeInOutCirc',
    Elastic: 'easeInOutElastic',
    Back: 'easeInOutBack',
    Bounce: 'easeInOutBounce'
  }
};
Fsz.form = {
  toJSON: function() {
    var element = this;
  },
  getData: function(element) {
    var form = element;
    var fields = [];
    var inputs = Fsz.$$(':input', form);
    //console.log(inputs);
    var data = {};
    inputs.each(function(el) {
      if (false == el.name) {
        return false;
      }
      if (el.nodeName == 'INPUT') {
        switch (el.type) {
        case 'text':
        case 'hidden':
          data[el.name] = this.getTextFieldValue(el);
          break;
        case 'radio':
          if (el.checked == true) {
            data[el.name] = el.value;
          }
          break;
        case 'checkbox':
          if (!data[el.name]) {
            data[el.name] = [];
          }

          if (el.checked == true) {
            data[el.name].push(el.value);
          }
          break;
        }
      } else if (el.nodeName == 'SELECT') {
        data[el.name] = this.getSelectBoxValue(el);
      } else if (el.nodeName == 'TEXTAREA') {
        data[el.name] = this.getTextareaValue(el);
      } else if (el.nodeName == 'BUTTON') {
        data[el.name] = el.value;
      }

    }.bind(this));
    return data;
  },
  getTextFieldValue: function(textfield) {
    return textfield.value;
  },
  getRadioButtonValue: function(radioButtons) {

  },
  getCheckBoxValue: function(checkboxes) {},
  getSelectBoxValue: function(selectbox) {
    return selectbox.value;
  },
  getTextareaValue: function(textarea) {
    return textarea.value;
  },
  reset: function(element) {
    var form = element;
    var inputs = Fsz.$$(':input', form);
    //console.log(inputs);
    inputs.each(function(el) {
      if (false == el.name) {
        return false;
      }
      if (el.nodeName == 'INPUT') {
        switch (el.type) {
        case 'text':
        case 'hidden':
          el.value = '';
          break;
        case 'radio':
          el.checked = false;
          break;
        case 'checkbox':
          el.checked = false;
          break;
        }
      } else if (el.nodeName == 'SELECT') {} else if (el.nodeName == 'TEXTAREA') {
        el.value = '';
      }
    }.bind(this));
  }
};


/**
 * Ajax Methods.
 * @author juniac, hamdalf(IE9 patch)
 * @date 2010-10-21
 */
Fsz.Ajax = function() {};
Fsz.Ajax.Factory = function() {
  if (Fsz.browser.isIE9Under() == false && window.XMLHttpRequest) {
    var XHRModel = new XMLHttpRequest();
  } else {
    try {
      XHRModel = new ActiveXObject('Msxml2.XMLHTTP') || new ActiveXObject('Microsoft.XMLHTTP');
    } catch (e) {}
  }
  return XHRModel;
};
Fsz.Ajax.Responder = function(r, method) {
  var contentType = r.getResponseHeader("content-type");
  var data = !method && contentType && /xml/.test(contentType);
  data = method == "xml" || data ? r.responseXML : r.responseText;
  return data;
};
Fsz.Ajax.httpSuccess = function(r) {
  try {
    return !r.status && location.protocol == "file:" || (r.status >= 200 && r.status < 300) || r.status == 304 || Fsz.browser.isSafari() && typeof r.status == "undefined";
  } catch (e) {}
};

Fsz.Ajax.Request = Fsz.Class({
  options: {},
  initialize: function(url, options) {
    this.setOption(options);
    var data = [],
      queryString = '';

    for (var p in options.parameters) {
      data.push(p + '=' + encodeURIComponent(options.parameters[p]));
    }
    queryString = data.join('&');
    if (this.options.method == 'GET') {
      if (/\?/.test(url) && queryString.length > 0) {
        queryString = '&' + queryString;
      } else {
        queryString = '?' + queryString;
      }
      url += queryString;
    } else {}
    var response = null;
    var that = this;
    var XHR = Fsz.Ajax.Factory();
    XHR.open(this.options.method, url, this.options.asynchronous, this.options.user, this.options.password);


    var timeoutLength = this.options.timeout * 1000;
    var requestDone = false;
    setTimeout(function() {
      requestDone = true;
    }, timeoutLength);
    XHR.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
    XHR.setRequestHeader("charset", "utf=8");
    //if(XHR.overrideMimeType) {
    //XHR.setRequestHeader('Connection', 'close');
    //}
    if (XHR.overrideMimeType && (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0, 2005])[1] < 2005) {
      //XHR.setRequestHeader('Connection', 'close');
    }

    XHR.onreadystatechange = function() {
      try {
        if (XHR.readyState == 4 && requestDone == false) {
          if (Fsz.Ajax.httpSuccess(XHR)) {
            response = Fsz.Ajax.Responder(XHR, that.options.method);
          }
          that.options.onComplete(response);
          XHR = null;
        };
      } catch (e) {
        that.options.onError(e);
      } finally {
        //response = Fsz.Ajax.Responder(XHR, that.options.method);
      }
    }
    XHR.send(queryString);

    if (this.options.asynchronous == false) {
      try {
        if (XHR.readyState == 4 && requestDone == false) {
          if (Fsz.Ajax.httpSuccess(XHR)) {
            response = Fsz.Ajax.Responder(XHR, that.options.method);
          }
          that.options.onComplete(response);
          XHR = null;
        };
      } catch (e) {
        that.options.onError(e);
      } finally {}
    }
  },
  setOption: function(options) {
    this.options = {};
    if (options.asynchronous == undefined) {
      options.asynchronous = true;
    }
    if (options.user == undefined) {
      options.user = null;
    }
    if (options.password == undefined) {
      options.password = null;
    }
    this.options.timeout = options.timeout || 5;
    this.options.asynchronous = options.asynchronous;
    this.options.user = options.user;
    this.options.password = options.password;

    this.options.method = (options.method || 'post').toUpperCase();
    this.options.data = {};

    if (options.parameters) {
      for (var d in options.parameters) {
        this.options.data[d] = options.parameters[d];
      }
    }
    this.options.onComplete = options.onComplete ||
    function(req) {};
    this.options.onError = options.onError ||
    function(e) {};
  }
});

Fsz.Ajax.Update = Fsz.Class({
  initialize: function(element, url, options) {
    if (Fsz.getType(element) == 'String') {
      element = Fsz.$(element);
    }
    var newOptions = options;
    var onComplete = options.onComplete || null;
    newOptions.onComplete = function(response) {
      element.innerHTML = response;
      //options.onComplete();
      onComplete(response);
    };
    new Fsz.Ajax.Request(url, newOptions);
  }
});

Fsz.flash = {
  get: function(id) {
    if (Fsz.browser.isIE9Under()) {
      var w = window;
      var flashElement = w[id];
    } else {
      var d = document;
      flashElement = d[id];
    }
    return flashElement;
  }
};
Fsz.findFlashElementById = Fsz.flash;
/**
 * Utility Method Library.
 * 자주 사용되지만 일일히 작성할 필요 없게 메쏘드로 작성해 놓음.
 * @author juniac, hamdalf(IE9 patch)
 * @date 2010-10-21
 */
Fsz.util = {
  random: function() {},
  includeJS: function(url, handler) {
    var head = Fsz.d.getElementsByTagName('head')[0];
    var script = Fsz.$E('script');
    script.setAttribute('content', 'text/javascript');
    script.setAttribute('src', url);
    head.appendChild(script);
    script.onload = handler;
  },
  includeCSS: function(url, handler) {},
  preventRightMouseButtonEvent: function() {
    var body = Fsz.$$('body');
    if (body.length == 0) {
      return false;
    }
    if (Fsz.browser.isIE()) {
      if (body.length > 0) {
        body[0].oncontextmenu = function() {
          return false;
        };
      }
    } else {
      var onclickHandler = function(e) {
          if (false == Event.isLeftClick(e)) {
            Event.stop(e);
          }
        }
      document.captureEvents(Event.CLICK);
      document.onclick = onclickHandler;
      document.onmouseup = onclickHandler;
      document.ondblclick = onclickHandler;
    }
  }
};